package com.haredot.filter;

import org.springframework.util.StreamUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;

/**
 * 处理 JSON 请求 获取 控制器中对应的 JSON参数
 *
 */
public class RequestBodyFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        if (!request.getContentType().startsWith("application/json")) {
            filterChain.doFilter(request, response);
            return ;
        }

        // 构建一个 自定义 请求对象，用来处理特殊的 事情
        RequestBodyHttpServletRequest requestBodyHttpServletRequest = new RequestBodyHttpServletRequest(request);

        filterChain.doFilter(requestBodyHttpServletRequest, response);
    }

    /**
     * 自定义一个 请求， 存储一个 byte[] 数组，内存放 数据
     */
    static class RequestBodyHttpServletRequest extends HttpServletRequestWrapper {

        private final byte[] bytes  ;

        public RequestBodyHttpServletRequest(HttpServletRequest request) throws IOException {
            super(request);
            ServletInputStream inputStream = request.getInputStream();
            // 将 请求中的参数 读取并存储到 byte[]中
            bytes = StreamUtils.copyToByteArray(inputStream);
        }

        /**
         * 构建一个可多次读写的流
         * @return
         * @throws IOException
         */
        @Override
        public ServletInputStream getInputStream() throws IOException {
            return new RequestBodyServletInputStream(bytes);
        }
    }

    /**
     * 自定义一个 ServletInputStream 类，用来处理
     */
    static class RequestBodyServletInputStream extends ServletInputStream {

        private ByteArrayInputStream bis ;

        private RequestBodyServletInputStream(byte[] bytes) {
            bis = new ByteArrayInputStream(bytes);
        }

        @Override
        public boolean isFinished() {
            return bis.available() == 0 ;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {

        }

        @Override
        public int read() throws IOException {
            return bis.read();
        }
    }
}
